/*  This file is part of -_-.

    -_- is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    -_- is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with -_-.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2012-2013 Oliver Katz */

#ifndef __BUS_IPC_H
#define __BUS_IPC_H

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include "../common/data.h"

//struct z_ipc_server: an interprocess communication server
typedef struct
{
	int domain; //memberof z_ipc_server: the domain
	int listenfd; //memberof z_ipc_server: the file descriptor to listen on
	int confd; //memberof z_ipc_server: the connection file descriptor
	int port; //memberof z_ipc_server: the port to serve on
	struct sockaddr_in server; //memberof z_ipc_server: server info
} z_ipc_server;

z_ipc_server z_ipc_server_init(int port, int domain);
z_ipc_server z_ipc_server_init_global(int port); //methodof z_ipc_server: initialize a global IPC server
z_ipc_server z_ipc_server_init_local(int port); //methodof z_ipc_server: initialize a local IPC server
z_ipc_server *z_ipc_server_new_global(int port); //methodof z_ipc_server: allocator
z_ipc_server *z_ipc_server_new_local(int port); //methodof z_ipc_server: allocator
int z_ipc_server_release(z_ipc_server i); //methodof z_ipc_server: uninitializer
int z_ipc_server_delete(z_ipc_server *i);
int z_ipc_server_connect(z_ipc_server *i); //methodof z_ipc_server: connect to server
int z_ipc_server_disconnect(z_ipc_server *i); //methodof z_ipc_server: disconnect from server
z_data z_ipc_server_wait(z_ipc_server *i, int *p, char **a); //methodof z_ipc_server: wait for a request
z_data *_z_ipc_server_wait(z_ipc_server *i);
int z_ipc_server_reply(z_ipc_server *i, z_data *d); //methodof z_ipc_server: reply to a request
int z_ipc_server_reply_empty(z_ipc_server *i); //methodof z_ipc_server: reply to a request with no return data

//struct z_ipc_client: an interprocess communication client
typedef struct
{
	int sock; //memberof z_ipc_client: socket file descriptor
	int port; //memberof z_ipc_client: the port to connect to
	char *addr; //memberof z_ipc_client: the ip address to connect to
	int domain; //memberof z_ipc_client: the domain
	struct sockaddr_in server; //memberof z_ipc_client: server info
} z_ipc_client;

z_ipc_client z_ipc_client_init(char *addr, int port, int domain);
z_ipc_client z_ipc_client_init_global(char *addr, int port); //methodof z_ipc_client: initialize a global IPC client
z_ipc_client z_ipc_client_init_local(char *addr, int port); //methodof z_ipc_client: initialize a local IPC client
z_ipc_client *z_ipc_client_new_global(char *addr, int port); //methodof z_ipc_client: allocator
z_ipc_client *z_ipc_client_new_local(char *addr, int port); //methodof z_ipc_client: allocator
int z_ipc_client_release(z_ipc_client i); //methodof z_ipc_client: uninitializer
int z_ipc_client_delete(z_ipc_client *i); //methodof z_ipc_client: deletor
int z_ipc_client_connect(z_ipc_client *i); //methodof z_ipc_client: connect to server
//returnof z_ipc_client_connect: int: 0 on success, 1 on failure to open socket, and 2 on failure to connect to server
int z_ipc_client_disconnect(z_ipc_client *i); //methodof z_ipc_client: disconnect from server
int z_ipc_client_send_request(z_ipc_client *i, z_data *req); //methodof z_ipc_client: send a request to the server
z_data z_ipc_client_recieve_response(z_ipc_client *i); //methodof z_ipc_client: recieve the server responce
z_data *_z_ipc_client_recieve_response(z_ipc_client *i);

/// This is the most basic form of TCP interprocess communication. It's used by bus/share.h. 
///
/// Here's a basic example:
/// {{char *text = "I wanna send this from a client to a server";
/// z_data data = z_data_wrap(text, strlen(text)*sizeof(char));
///
/// // let's start with making a client to send them
/// z_ipc_client client = z_ipc_client_init_global("127.0.0.1", 8950);
///
/// // now let's make a server to recieve them
/// z_ipc_server server = z_ipc_server_init_global(8950);
/// z_ipc_server_connect(&server);
///
/// // next let's connect to the server and send some text
/// z_ipc_client_connect(&client);
/// z_ipc_client_send_request(&client, &data);
/// z_data request = z_ipc_server_wait(&server);
/// z_ipc_server_reply_empty(&server);
/// z_ipc_client_recieve_response(&client);
///
/// // the following should print the contents of 'text'
/// printf("%s\n", (char *)z_data_src_get(&request));}}

#endif
